package com.xjd.transport.work;

import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;

import com.xjd.transport.TransportRuntimeException;


public class WorkExecutor {
	
	protected Queue<Work> workQueue = new LinkedBlockingQueue<Work>();
	protected Map<Work, Thread> workThreadMap = new HashMap<Work, Thread>();
	
	protected Work currentWork;
	
	protected ExecutorService workerExecutorService;
	
	public WorkExecutor(ExecutorService service) {
		this.workerExecutorService = service;
	}
	
	public void execute(Work work, boolean async) {
		synchronized (work) {
			boolean executeImmediately = false;
			synchronized (workQueue) {
				if (!workQueue.offer(work)) {
					throw new TransportRuntimeException("'worker queue' is full");
				}
				work.setExecutor(this);
				if (!async) {
					workThreadMap.put(work, Thread.currentThread());
				}

				if (workQueue.size() == 1 && currentWork == null) {
					currentWork = workQueue.poll();
					if (currentWork == null) {
						throw new TransportRuntimeException("Invalid lock status.");
					}
					executeImmediately = true;
				}
			}
			if (async) {
				if (currentWork == work && executeImmediately) {
					if (workerExecutorService != null) {
						workerExecutorService.execute(work);
					} else {
						work.start(); //如果没有ThreadPool
					}
				}
			} else {
				if (currentWork == work && executeImmediately) {
					work.run();
				} else {
					Throwable t;
					do {
						t = null;
						try {
							work.wait(); // 等待换醒
						} catch (InterruptedException e) {
							t = e;
						}
					} while (t != null);
					work.run();
				}
			}
		}
	}
	
	public void executeNext() {
		Thread t = null;
		synchronized (workQueue) {
			workThreadMap.remove(currentWork);
			currentWork = workQueue.poll();
			if (currentWork == null) {
				return;
			}
			t = workThreadMap.get(currentWork);
		}

		if (t == null) {
			if (workerExecutorService != null) {
				workerExecutorService.execute(currentWork);
			} else {
				currentWork.start(); //如果没有ThreadPool
			}
		} else {
			synchronized (currentWork) {
				currentWork.notifyAll();
			}
		}
	}
}
